package com.zhiyin.seal.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhiyin.seal.dao.*;
import com.zhiyin.seal.entity.*;
import com.zhiyin.seal.entity.bo.*;
import com.zhiyin.seal.service.ApplyService;
import com.zhiyin.seal.util.BeanUtil;
import com.zhiyin.seal.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ApplyServiceImpl implements ApplyService {

    @Autowired
    ApplyDao applyDao;

    @Autowired
    SealDao sealDao;

    @Autowired
    UserDao userDao;

    @Autowired
    CompanyDao companyDao;

    @Autowired
    CompanyUserDao companyUserDao;

    @Autowired
    ApprovalDao approvalDao;

    @Autowired
    FileDao fileDao;

    @Autowired
    StampDao stampDao;

    @Override
    public Boolean addUseSealApply(ApplyBo applyBo) {
        // 单据编码
        String code = StringUtil.GenerateApplyCode(applyBo.getCompanyId() + "");
        applyBo.setCode(code);

        ApplyEntity applyEntity = BeanUtil.copy(applyBo,ApplyEntity.class);
        // 插入单据
        applyDao.insertApply(applyEntity);
        Long applyId = applyEntity.getId();
        applyBo.setId(applyId);
        if(applyId == 0){
            return false;
        }
        // 插入上传图片
        List<String> imgUrls = applyBo.getImageUrls();
        if(imgUrls != null && imgUrls.size() > 0){
            List<ApplyPhotoBo> applyPhotoBoList = Lists.newArrayList();
            for(int i = 0;i<imgUrls.size();i++){
                String imageUrl = imgUrls.get(i);
                ApplyPhotoBo applyPhotoBo = new ApplyPhotoBo();
                applyPhotoBo.setApplyId(applyId);
                applyPhotoBo.setImageUrl(imageUrl);
                applyPhotoBo.setType(1);
                applyPhotoBoList.add(applyPhotoBo);
            }
            List<ApplyPhotoEntity> applyPhotoEntityList = BeanUtil.copyList(applyPhotoBoList,ApplyPhotoEntity.class);
            if(applyPhotoEntityList.size() > 0){
                // 插入图片信息
                applyDao.insertApplyPhotoList(applyPhotoEntityList);
                // 插入pdf任务
                applyDao.insertApplyPdfTask(applyId);
            }
        }
        // 更新上传附件
        List<String> fileUrls = applyBo.getFileUrls();
        if(fileUrls!= null && fileUrls.size() > 0){
            fileDao.updateAttachmentApplyId(applyId,fileUrls);
        }
        // 拷贝审批人
        applyDao.insertApplyApproval(applyBo.getId(),applyBo.getApprovalProcessId());
        // 拷贝抄送人
        applyDao.insertApplyCC(applyBo.getId(),applyBo.getApprovalProcessId());
        // 启动审批流
        applyDao.updateMyApprovalFirst(applyBo.getId());

        return true;
    }

    @Override
    public ApplyBo getApplyInfo(Long applyId) {
        ApplyEntity applyEntity = applyDao.selectApplyInfo(applyId);
        if(applyEntity != null){
            return BeanUtil.copy(applyEntity,ApplyBo.class);
        }

        return null;
    }

    @Override
    public List<ApplyBo> getApplyListByIds(List<Long> applyIdList) {
        List<ApplyEntity> applyEntityList = applyDao.selectApplyListByIds(applyIdList);
        if(applyEntityList != null){
            return BeanUtil.copyList(applyEntityList,ApplyBo.class);
        }

        return null;
    }

    @Override
    public List<ApplyBo> getStampRecordApplyList(StampSearchParamsBo stampSearchParamsBo) {
        List<ApplyEntity> applyEntityList = stampDao.selectStampRecordApplyList(BeanUtil.copy(stampSearchParamsBo,StampSearchParamsEntity.class));
        if(applyEntityList != null){
            return BeanUtil.copyList(applyEntityList,ApplyBo.class);
        }

        return null;
    }

    @Override
    public List<ContractTypeBo> getContractTypeList() {
        return BeanUtil.copyList(applyDao.selectContractTypeList(),ContractTypeBo.class);
    }

    @Override
    public List<ContractTypeBo> getCompanyContractList(Long companyId) {
        return BeanUtil.copyList(applyDao.selectCompanyContractList(companyId),ContractTypeBo.class);
    }

    @Override
    public List<ApplyOfMyBo> getAvailableApplyList(Long userId) {
        List<ApplyEntity> applyEntityList = applyDao.selectAvailableApplyList(userId);
        return buildMyApplyList(applyEntityList);
    }

    @Override
    public Long getMyApplyTotalCount(ApplySearchParamsBo paramsBo) {
        return applyDao.selectMyApplyTotalCount(BeanUtil.copy(paramsBo, ApplySearchParamsEntity.class));
    }

    @Override
    public List<ApplyOfMyBo> getMyApplyList(ApplySearchParamsBo paramsBo) {
        List<ApplyEntity> applyEntityList = applyDao.selectMyApplyList(BeanUtil.copy(paramsBo, ApplySearchParamsEntity.class));
        return buildMyApplyList(applyEntityList);
    }

    @Override
    public Long getMyApprovalTotalCount(ApplySearchParamsBo paramsBo) {
        return applyDao.selectMyApprovalTotalCount(BeanUtil.copy(paramsBo, ApplySearchParamsEntity.class));
    }

    @Override
    public List<ApplyOfMyApprovalBo> getMyApprovalList(ApplySearchParamsBo paramsBo) {
        List<ApplyEntity> applyEntityList = applyDao.selectMyApprovalList(BeanUtil.copy(paramsBo,ApplySearchParamsEntity.class));
        return buildMyApprovalList(applyEntityList);
    }

    @Override
    public Long getMyCCTotalCount(ApplySearchParamsBo paramsBo) {
        return applyDao.selectMyCCTotalCount(BeanUtil.copy(paramsBo, ApplySearchParamsEntity.class));
    }

    @Override
    public List<ApplyOfMyCCBo> getMyCCList(ApplySearchParamsBo paramsBo) {
        List<ApplyEntity> applyEntityList = applyDao.selectMyCCList(BeanUtil.copy(paramsBo,ApplySearchParamsEntity.class));
        return buildMyCCList(applyEntityList);
    }

    @Override
    public ApplyBo getExpireApplySingle() {
        List<ApplyEntity> applyEntityList = applyDao.selectExpireApply();
        if(applyEntityList != null && applyEntityList.size() > 0){
            return BeanUtil.copy(applyEntityList.get(0),ApplyBo.class);
        }

        return null;
    }

    @Override
    public List<PdfTaskBo> getPendingPdfTaskList() {
        List<PdfTaskEntity> pdfTaskEntityList = applyDao.selectPendingPdfTaskList();

        return BeanUtil.copyList(pdfTaskEntityList,PdfTaskBo.class);
    }

    @Override
    public List<ApplyPhotoBo> getApplyImageList(Long applyId, Integer type) {
        List<ApplyPhotoEntity> applyPhotoEntityList = applyDao.selectApplyImageList(applyId,type);

        return BeanUtil.copyList(applyPhotoEntityList,ApplyPhotoBo.class);
    }

    @Override
    public Boolean replaceApply(Long applyId, Long userId) {
        return applyDao.updateApplyStampUser(applyId,userId) > 0;
    }

    @Override
    public Boolean revokeApply(Long applyId) {
        return applyDao.updateApplyRevoke(applyId) > 0;
    }

    @Override
    public Boolean approvalApply(ApprovalParamsBo paramsBo) {
        ApprovalParamsEntity approvalParamsEntity = BeanUtil.copy(paramsBo, ApprovalParamsEntity.class);
        // 查询单据审批进度
        List<MyApprovalEntity> myApprovalEntityList = applyDao.selectApprovalProgress(paramsBo.getApplyId());
        Integer currentLevel = -1;
        Integer lastLevel = -1;
        Long myApprovalId = 0l;
        for (MyApprovalEntity myApprovalEntity : myApprovalEntityList) {
            // 判断单据id，审批人员，处理状态为待审批
            if(myApprovalEntity.getApplyId().equals(paramsBo.getApplyId())
                    && myApprovalEntity.getUserId().equals(paramsBo.getUserId())
                    && myApprovalEntity.getStatus().equals(1)){
                // 找到第一个匹配的即可
                if(currentLevel.equals(-1)){
                    currentLevel = myApprovalEntity.getLevel();
                    myApprovalId = myApprovalEntity.getId();
                }
            }
            lastLevel = myApprovalEntity.getLevel();
        }
        // 判断当前节点是否存在
        if(currentLevel > -1){
            List<Long> myApprovalIdList = Lists.newArrayList();
            for (MyApprovalEntity myApprovalEntity : myApprovalEntityList) {
                if(myApprovalEntity.getLevel().equals(currentLevel)){
                    myApprovalIdList.add(myApprovalEntity.getId());
                }
            }
            // 更新当前审批人状态
            applyDao.updateMyApprovalHandleStatus(approvalParamsEntity,myApprovalId);
            // 更新当前审批节点处理状态
            applyDao.updateMyApprovalLevelHandleStatus(approvalParamsEntity,myApprovalIdList);
            // 如果同意审批
            if(paramsBo.getApprovalResult().equals(2)){
                // 判断是否为最后一个节点
                if(currentLevel.equals(lastLevel)){
                    // 更新单据审批状态和耗时
                    applyDao.updateApplyStatusAndTimeConsume(approvalParamsEntity);
                    // 更新单据审批意见
                    applyDao.updateApplyApprovalComment(approvalParamsEntity);
                    // 通知申请人审批结果
                    ApplyNotesEntity applyNotesEntity = applyDao.selectApplyNotesByApplyId(paramsBo.getApplyId());
                    if(applyNotesEntity == null){
                        applyDao.insertApplyNotes(approvalParamsEntity);
                    }
                } else {
                    // 单据状态为审批中
                    approvalParamsEntity.setApprovalResult(1);
                    applyDao.updateApplyStatusAndTimeConsume(approvalParamsEntity);
                    // 通知下一个审批节点
                    myApprovalIdList.clear();
                    Integer nextLevel = currentLevel + 1;
                    for (MyApprovalEntity myApprovalEntity : myApprovalEntityList) {
                        if(myApprovalEntity.getLevel().equals(nextLevel)){
                            myApprovalIdList.add(myApprovalEntity.getId());
                        }
                    }
                    applyDao.updateMyWaiteApprovalStatus(myApprovalIdList);
                }
            } else {
                // 更新单据审批状态和耗时
                applyDao.updateApplyStatusAndTimeConsume(approvalParamsEntity);
                // 更新单据审批意见
                applyDao.updateApplyApprovalComment(approvalParamsEntity);
                // 通知申请人审批结果
                ApplyNotesEntity applyNotesEntity = applyDao.selectApplyNotesByApplyId(paramsBo.getApplyId());
                if(applyNotesEntity == null){
                    applyDao.insertApplyNotes(approvalParamsEntity);
                }
            }
        }

        return true;
    }

    @Override
    public Boolean closeApply(Long applyId) {
        if(applyId == 0){
            return false;
        }
        applyDao.updateApplyClose(applyId);
        applyDao.insertStampPdfTask(applyId);

        return true;
    }

    @Override
    public Boolean getHasMyAvailableApply(Long userId) {
        return applyDao.selectHasMyAvailableApply(userId) > 0;
    }

    @Override
    public List<Long> getMyAvailableApply() {
        return applyDao.selectMyAvailableApply();
    }

    @Override
    public Boolean getHasMyApproval(Long userId) {
        return applyDao.selectHasMyApproval(userId) > 0;
    }

    @Override
    public Boolean updatePdfTaskStatus(Long taskId) {
        return applyDao.updatePdfTaskStatus(taskId) > 0;
    }

    @Override
    public Boolean updateApplyPdfUrl(Long applyId, String pdfUrl) {
        return applyDao.updateApplyPdfUrl(applyId,pdfUrl) > 0;
    }

    @Override
    public Boolean updateStampPdfUrl(Long applyId, String pdfUrl) {
        return applyDao.updateStampPdfUrl(applyId,pdfUrl) > 0;
    }

    @Override
    public ApplyDetailBo getApplyDetailInfo(Long applyId) {
        ApplyDetailBo applyDetailBo = BeanUtil.copy(applyDao.selectApplyInfo(applyId),ApplyDetailBo.class);
        SealEntity sealEntity = sealDao.selectSealByIdAndCompany(applyDetailBo.getSealId(),applyDetailBo.getCompanyId());
        CompanyEntity companyEntity = companyDao.selectCompanyById(applyDetailBo.getCompanyId());
        applyDetailBo.setSealInfo(BeanUtil.copy(sealEntity,SealBo.class));
        applyDetailBo.setCompanyInfo(BeanUtil.copy(companyEntity,CompanyBo.class));
        applyDetailBo.setApplyUserInfo(getUserInfoByIdAndCompany(applyDetailBo.getCreateUser(),applyDetailBo.getCompanyId()));
        applyDetailBo.setStampUserInfo(getUserInfoByIdAndCompany(applyDetailBo.getStampUser(),applyDetailBo.getCompanyId()));
        //审批进度
        List<MyApprovalEntity> myApprovalEntityList = applyDao.selectApprovalProgress(applyId);
        List<MyCCEntity> myCCEntityList = applyDao.selectCCProgress(applyId);
        // 构造审批流数据集合
        List<MyApprovalBo> myApprovalBoList = BeanUtil.copyList(myApprovalEntityList,MyApprovalBo.class);
        List<MyCCBo> myCCBoList = BeanUtil.copyList(myCCEntityList,MyCCBo.class);
        // 用户id集合
        List<Long> userIds = Lists.newArrayList();
        userIds.add(0l);
        if(myApprovalBoList != null){
            for (MyApprovalBo myApprovalBo : myApprovalBoList) {
                userIds.add(myApprovalBo.getUserId());
            }
        }

        if(myCCBoList != null){
            for (MyCCBo myCCBo : myCCBoList) {
                userIds.add(myCCBo.getUserId());
            }
        }
        // 用户id列表去重复
        userIds = userIds.stream().distinct().collect(Collectors.toList());
        List<UserBo> userBoList = getUserListByUserIdsAndCompany(userIds,applyDetailBo.getCompanyId());
        if(userBoList == null){
            return applyDetailBo;
        }
        Map<Long,UserBo> userBoMap = Maps.newHashMap();
        for (UserBo userBo : userBoList) {
            userBoMap.put(userBo.getId(),userBo);
        }
        // 赋值用户信息
        if(myApprovalBoList != null){
            for (MyApprovalBo myApprovalBo : myApprovalBoList) {
                myApprovalBo.setUserInfo(userBoMap.get(myApprovalBo.getUserId()));
            }
        } else {
            myApprovalBoList = Lists.newArrayList();
        }

        if(myCCBoList != null){
            for (MyCCBo myCCBo : myCCBoList) {
                myCCBo.setUserInfo(userBoMap.get(myCCBo.getUserId()));
            }
        } else {
            myCCBoList = Lists.newArrayList();
        }

        applyDetailBo.setApprovalList(myApprovalBoList);
        applyDetailBo.setCcList(myCCBoList);

        return applyDetailBo;
    }

    @Override
    public List<MyApprovalBo> getWaitApprovalList() {
        List<MyApprovalEntity> myApprovalEntityList = applyDao.selectWaiteApproval();
        return BeanUtil.copyList(myApprovalEntityList,MyApprovalBo.class);
    }

    @Override
    public Boolean updateWaiteApproval(List<Long> idList) {
        return applyDao.updateWaiteApproval(idList) > 0;
    }

    @Override
    public List<ApprovalSmsBo> getWaitApprovalSms() {
        List<ApprovalSmsEntity> approvalSmsEntityList = applyDao.selectWaiteApprovalSms();
        List<ApprovalSmsBo> approvalSmsBoList = BeanUtil.copyList(approvalSmsEntityList,ApprovalSmsBo.class);
        if(approvalSmsBoList.size() > 0){
            for(ApprovalSmsBo approvalSmsBo : approvalSmsBoList){
                UserEntity userEntity = userDao.getUserInfoById(approvalSmsBo.getApprovalUserId());
                if(userEntity != null){
                    UserBo userBo = BeanUtil.copy(userEntity,UserBo.class);
                    approvalSmsBo.setApprovalUser(userBo);
                }

                userEntity = userDao.getUserInfoById(approvalSmsBo.getApplyUserId());
                if(userEntity != null){
                    UserBo userBo = BeanUtil.copy(userEntity,UserBo.class);
                    approvalSmsBo.setApplyUser(userBo);
                }

            }
        }

        return approvalSmsBoList;
    }

    @Override
    public Boolean updateWaitApprovalSms(List<Long> idList) {
        return applyDao.updateWaiteApprovalSms(idList) > 0;
    }

    @Override
    public List<ApplyNotesBo> getApplyNotesList() {
        List<ApplyNotesEntity> applyNotesEntityList = applyDao.selectApplyNotes();
        return BeanUtil.copyList(applyNotesEntityList,ApplyNotesBo.class);
    }

    @Override
    public Boolean updateApplyNotes(List<Long> idList) {
        return applyDao.updateApplyNotes(idList) > 0;
    }

    @Override
    public Boolean updateApplyCloseBySealId(Long sealId) {
        return applyDao.updateApplyCloseBySealId(sealId) > 0;
    }


    protected List<ApplyOfMyBo> buildMyApplyList(List<ApplyEntity> applyEntityList){
        List<ApplyOfMyBo> applyOfMyBoList = BeanUtil.copyList(applyEntityList, ApplyOfMyBo.class);
        if(applyOfMyBoList != null){
            for (ApplyOfMyBo applyOfMyBo : applyOfMyBoList) {
                SealEntity sealEntity = sealDao.selectSealByIdAndCompany(applyOfMyBo.getSealId(),applyOfMyBo.getCompanyId());
                applyOfMyBo.setSealInfo(BeanUtil.copy(sealEntity,SealBo.class));
            }

            return applyOfMyBoList;
        }

        return null;
    }

    protected  List<ApplyOfMyApprovalBo> buildMyApprovalList(List<ApplyEntity> applyEntityList){
        List<ApplyOfMyApprovalBo> approvalBoList = BeanUtil.copyList(applyEntityList,ApplyOfMyApprovalBo.class);
        if(approvalBoList != null){
            for (ApplyOfMyApprovalBo myApprovalBo : approvalBoList) {
                SealEntity sealEntity = sealDao.selectSealByIdAndCompany(myApprovalBo.getSealId(),myApprovalBo.getCompanyId());
                myApprovalBo.setSealInfo(BeanUtil.copy(sealEntity,SealBo.class));
            }
            for (ApplyOfMyApprovalBo myApprovalBo : approvalBoList) {
                UserBo userBo = getUserInfoByIdAndCompany(myApprovalBo.getCreateUser(),myApprovalBo.getCompanyId());
                myApprovalBo.setUserInfo(userBo);
            }

            return approvalBoList;
        }

        return null;
    }

    protected List<ApplyOfMyCCBo> buildMyCCList(List<ApplyEntity> applyEntityList){
        List<ApplyOfMyCCBo> ccBoList = BeanUtil.copyList(applyEntityList,ApplyOfMyCCBo.class);
        if(ccBoList != null){
            // 赋值印章实体和用户实体
            for (ApplyOfMyCCBo myCClBo : ccBoList) {
                SealEntity sealEntity = sealDao.selectSealByIdAndCompany(myCClBo.getSealId(),myCClBo.getCompanyId());
                myCClBo.setSealInfo(BeanUtil.copy(sealEntity,SealBo.class));
            }
            for (ApplyOfMyCCBo myCClBo : ccBoList) {
                UserBo userBo = getUserInfoByIdAndCompany(myCClBo.getCreateUser(),myCClBo.getCompanyId());
                myCClBo.setUserInfo(userBo);
            }

            return ccBoList;
        }

        return null;
    }

    protected UserBo getUserInfoByIdAndCompany(Long userId,Long companyId){
        CompanyUserEntity companyUserEntity = companyUserDao.selectCompanyUser(userId,companyId);
        if(companyUserEntity != null){
            UserEntity userEntity = userDao.getUserInfoById(companyUserEntity.getUserId());
            if(userEntity != null){
                UserBo userBo = BeanUtil.copy(userEntity,UserBo.class);
                userBo.setNickName(companyUserEntity.getUserAlias());

                return userBo;
            }
        }

        return null;
    }

    protected List<UserBo> getUserListByUserIdsAndCompany(List<Long> userIdList,Long companyId){
        if(userIdList.size() == 0){
            userIdList.add(0l);
        }
        List<CompanyUserEntity> companyUserEntityList = companyUserDao.selectUserListByIdsAndCompanyId(userIdList,companyId);
        if(companyUserEntityList != null){
            List<UserBo> userBoList = Lists.newArrayList();
            for (CompanyUserEntity companyUserEntity : companyUserEntityList){
                UserEntity userEntity = userDao.getUserInfoById(companyUserEntity.getUserId());
                if(userEntity != null){
                    UserBo userBo = BeanUtil.copy(userEntity,UserBo.class);
                    userBo.setNickName(companyUserEntity.getUserAlias());
                    userBoList.add(userBo);
                }
            }
            return userBoList;
        }

        return null;
    }
}